package pers.yefeng.config;


import pers.yefeng.base.View;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.InvalidPropertyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


/**
 * 全局异常 统一处理类
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 全局异常捕获
     *
     * @param e 异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public View<Object> error(Exception e) {
        log.error("系统繁忙，请稍后再试", e);
        return View.error("系统繁忙，请稍后再试。");
    }

    /**
     * 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是org.springframework.web.bind.MissingServletRequestParameterException
     *
     * @param e 异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public View<Object> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        log.error("参数'" + e.getParameterName() + "'不能为空！");
        return View.error("参数'" + e.getParameterName() + "'不能为空！");
    }


    /**
     * 请求参数解析错误异常
     *
     * @param e HttpMessageNotReadableException: JSON parse error
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public View<Object> error(HttpMessageNotReadableException e) {
        log.error("请求参数解析错误，{}", e);
        return View.error("请求参数解析错误！");
    }

    /**
     * 表单验证异常信息捕捉
     *
     * @param e HttpMessageNotReadableException: JSON parse error
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public View<Object> error(MethodArgumentNotValidException e) {
        StringBuilder errorInfo = new StringBuilder();
        e.getBindingResult().getFieldErrors().forEach(error -> errorInfo.append(error.getField()).append(":").append(error.getDefaultMessage()).append(" | "));
        String errorMsg = errorInfo.toString();
        int length = errorMsg.length();
        log.warn(errorMsg);
        return View.error(errorMsg.substring(0, length <= 2 ? 0 : length - 2));
    }

    /**
     * http请求方式错误异常
     *
     * @param e HttpRequestMethodNotSupportedException
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public View<Object> error(HttpRequestMethodNotSupportedException e) {
        String[] supportedMethods = e.getSupportedMethods();
        if (supportedMethods == null || supportedMethods.length == 0) {
            return View.error(e.getMessage());
        }
        StringBuilder methods = new StringBuilder();
        for (String supportedMethod : supportedMethods) {
            methods.append(supportedMethod).append("|");
        }
        return View.error(e.getMessage() + ", expect methods：" + methods.toString().substring(0, methods.length() - 1));
    }

    /**
     * 表单校验异常
     *
     * @param e BindException
     **/
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public View<Object> validationExceptionHandler(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder errorMessage = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMessage.append(fieldError.getDefaultMessage()).append("!");
        }
        return View.error(errorMessage.toString());
    }

    /**
     * org.springframework.beans.InvalidPropertyException 异常
     *
     * @param e InvalidPropertyException
     */
    @ExceptionHandler(InvalidPropertyException.class)
    @ResponseBody
    public View<Object> invalidPropertyExceptionHandler(InvalidPropertyException e) {
        String message = e.getMessage();
        return View.error("参数解析异常：{}", message);
    }

    /**
     * HttpMediaTypeNotSupportedException 异常
     *
     * @param e InvalidPropertyException
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    @ResponseBody
    public View<Object> httpMediaTypeNotSupportedHandler(HttpMediaTypeNotSupportedException e) {
        String message = e.getMessage();
        return View.error("参数解析异常：{}", message);
    }

}
